<script setup lang="ts">
import { useThemeVars } from 'naive-ui'
import type { Slots, VNodeChild } from 'vue'
import { computed, onBeforeMount, onMounted, reactive, ref, renderSlot, useAttrs, useSlots, watch } from 'vue'
import { renderIcon } from '@/utils'
import { useApp } from '@/themes'
interface Options {
  label?: string
  value?: string
  icon?: string
  disabled?: string
  [index: string]: any
}
interface Props {
  type?: 'default' | 'primary' | 'info' | 'success' | 'warning' | 'error'
  size?: 'small' | 'medium' | 'large'
  direction?: 'row' | 'column'
  padding?: string
  iconRight?: boolean // 图标是否右侧
  iconSize?: number | string
  labelField?: string
  valueField?: string
  options: Options[]
  name?: string
  disabled?: boolean
  bgColor?: string
  border?: boolean
  block?: boolean
  vertical?: boolean
}
defineOptions({
  name: 'Segmented',
  inheritAttrs: false,
})
defineSlots<{
  default?: VNodeChild
  icon?: VNodeChild
}>()
const props = withDefaults(defineProps<Props>(), {
  type: 'default',
  labelField: 'label',
  valueField: 'value',
  iconRight: false,
  iconSize: 20,
  border: true,
  block: true,
  options: () => [],
})
const modeValue = defineModel<string | number | boolean | null>({
  default: null,
})
const emit = defineEmits<{
  (e: 'change', value: string | number | boolean | null, index: number): void
}>()
const segmentedRef = ref<any>()
const activeState = reactive({
  offset: 0,
  clientWidth: 0,
  clientHeight: 0,
})
const activeIndex = ref(0)
const { isDark } = useApp()
onBeforeMount(() => {
  if (modeValue.value === null) {
    modeValue.value = props.options[0].value || ''
  }
})
const setLine = (index: number) => {
  if (segmentedRef.value) {
    // @ts-ignore
    const el = segmentedRef.value!.$el
    const itemEls = el.querySelectorAll('.w-segmented-item')
    if (itemEls) {
      const heights: number[] = []
      for (let i = 0; i < itemEls.length; i++) {
        heights.push(itemEls[i].clientHeight)
      }
      activeState.clientHeight = Math.max(...heights)
      activeState.clientWidth = itemEls[index].clientWidth
      if (props.vertical) {
        activeState.offset = itemEls[index].offsetTop
      } else {
        activeState.offset = itemEls[index].offsetLeft
      }
    }
  }
}
watch(modeValue, () => {
  activeIndex.value = getIndex()
  setLine(activeIndex.value)
})
const getIndex = () => {
  return props.options.findIndex(item => item[props.valueField] === modeValue.value)
}
onMounted(() => {
  if (segmentedRef.value) {
    setLine(getIndex())
  }
})
const themeVars = useThemeVars()
const colors = computed(() => {
  return {
    default: 'var(--default-color)',
    primary: themeVars.value.primaryColor,
    info: themeVars.value.infoColor,
    success: themeVars.value.successColor,
    warning: themeVars.value.warningColor,
    error: themeVars.value.errorColor,
  }
})
const sizes = { small: 12, medium: 14, large: 18 }
const bgColor = computed(() => (props.bgColor ? props.bgColor : isDark.value ? 'rgba(77,77,77,1)' : 'rgba(233,233,233,0.66)'))
const segmentedStyle = computed(() => {
  return {
    '--segmented-width': props.vertical ? '100%' : 'fit-content',
    '--segmented-disabled': props.disabled,
    '--segmented-direction': props.direction,
    '--segmented-background': bgColor.value,
    '--segmented-font-size': `${props.size ? sizes[props.size] : 14}px`,
    '--segmented-border': props.border ? '2px solid var(--segmented-background)' : '',
    '--segmented-transform': props.vertical ? `translateY(${activeState.offset}px)` : `translateX(${activeState.offset}px)`, // (activeState.offset)+'px',
    '--segmented-line-width': `${activeState.clientWidth}px`,
    '--segmented-line-height': `${activeState.clientHeight}px`,
    '--segmented-active-background': colors.value[props.type],
    '--segmented-active-color': props.type === 'default' ? '#333' : themeVars.value.baseColor,
  }
})
const attrs = useAttrs()
const slots = useSlots()
const renderOption = (option: Record<string, any>) => {
  return renderSlot(slots as Slots, 'default', option)
}

const renderIconSlot = (option: Record<string, any>) => {
  return slots?.icon ? renderSlot(slots as Slots, 'icon', option) : option?.icon ? renderIcon(option.icon, Number(props.iconSize)) : null
}

const onClick = (option: any, index: number) => {
  if (activeIndex.value !== index) {
    modeValue.value = option[props.valueField]
    activeIndex.value = index
    setLine(index)
    emit('change', modeValue.value, index)
  }
}
// class="absolute bottom-[5px] left-0 right-0 h-[1px] bg-red-500"
</script>

<template>
  <n-flex ref="segmentedRef" :vertical="vertical" class="w-segmented" :style="segmentedStyle" v-bind="$attrs">
    <div class="w-segmented-item-line" />
    <template v-for="(option, index) in options" :key="index">
      <div
        class="w-segmented-item"
        :class="{
          'w-segmented-item_active': option[valueField || 'label'] == modeValue,
        }"
        @click="onClick(option, index)"
      >
        <component :is="renderIconSlot(option)" v-if="!iconRight"></component>
        <component :is="renderOption(option)" v-if="slots.default"></component>
        <template v-else>{{ option[labelField || 'value'] }}</template>
        <component :is="renderIconSlot(option)" v-if="iconRight"></component>
      </div>
    </template>
  </n-flex>
</template>

<style lang="scss" scoped>
.w-segmented {
  position: relative;
  border-radius: 4px;
  background: var(--segmented-background);
  border: var(--segmented-border);
  width: var(--segmented-width);
  box-sizing: border-box;
  gap: 5px !important;

  .w-segmented-item {
    min-width: 60px;
    position: relative;
    cursor: pointer;
    border-radius: 4px;
    outline: unset !important;
    transition: all 0.6s;
    display: inline-flex;
    justify-content: center;
    align-items: center;
    padding: 4px 8px;
    flex-direction: var(--segmented-direction);
    font-size: var(--segmented-font-size);
    gap: 0 4px;
    &:not(.w-segmented-item_active) {
      &:hover {
        background: var(--hover-color);
      }
    }
    &.w-segmented-item_active {
      color: var(--segmented-active-color);
    }
    .w-segmented-item-icon-close {
      display: flex;
      justify-content: center;
      align-items: center;
      padding: 1px;
      margin-left: 2px;
      &:hover {
        background: rgba(0, 0, 0, 0.5);
        color: #ffffff;
        border-radius: 50%;
      }
    }
  }
  .w-segmented-item-line {
    position: absolute;
    transform: var(--segmented-transform);
    background: var(--segmented-active-background);
    color: var(--segmented-active-color);
    width: var(--segmented-line-width);
    height: var(--segmented-line-height);
    border-radius: 4px;
    transition: all 0.5s;
  }
}
</style>
